package ace.module.product.core.impl.manager.impl;

import ace.cmp.core.constants.CoreConstant;
import ace.cmp.data.spring.data.jdbc.querydsl.rsql.core.model.SaveContext;
import ace.cmp.data.spring.data.jdbc.querydsl.rsql.core.utils.SaveContextUtils;
import ace.cmp.util.AceAssertUtils;
import ace.cmp.util.AceNumberUtils;
import ace.cmp.util.AceStreamUtils;
import ace.module.common.core.impl.manager.impl.AbstractEntityOfAppManager;
import ace.module.product.api.model.dto.PmsProductAttributeDto;
import ace.module.product.api.model.input.PmsProductAttributeSaveInput;
import ace.module.product.api.model.input.PmsProductAttributeValueSaveInput;
import ace.module.product.core.impl.dao.entity.PmsProduct;
import ace.module.product.core.impl.dao.entity.PmsProductAttribute;
import ace.module.product.core.impl.dao.entity.PmsProductAttributeValue;
import ace.module.product.core.impl.dao.entity.PmsSpecAttribute;
import ace.module.product.core.impl.dao.model.bo.PmsProductAttributeAndValueBo;
import ace.module.product.core.impl.dao.model.bo.PmsProductAttributeBo;
import ace.module.product.core.impl.dao.repository.PmsProductAttributeRepository;
import ace.module.product.core.impl.dao.repository.PmsSpecAttributeRepository;
import ace.module.product.core.impl.manager.PmsProductAttributeManager;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;

/**
 * 商品规格属性 spring data jdbc querydsl rsql manager implement.
 *
 * @author Caspar
 */
@Slf4j
@AllArgsConstructor
@Component
public class PmsProductAttributeManagerImpl
    extends AbstractEntityOfAppManager<PmsProductAttribute, Long, PmsProductAttributeDto>
    implements PmsProductAttributeManager {

  private final PmsSpecAttributeRepository pmsSpecAttributeRepository;
  private final PmsProductAttributeRepository pmsProductAttributeRepository;

  @Override
  public Optional<PmsProductAttribute> findByName(List<PmsProductAttribute> productAttributes, String name) {
    return AceStreamUtils.ofNullable(productAttributes)
        .filter(p -> StringUtils.equalsAnyIgnoreCase(p.getName(), name))
        .findFirst();
  }

  @Override
  public PmsProductAttributeBo assembleProductAttributeBos(List<PmsProductAttributeSaveInput> pmsProductAttributeSaveInputs, PmsProduct product) {
    List<PmsProductAttributeAndValueBo> pmsProductSpecAttributeBos = pmsProductAttributeSaveInputs
        .stream()
        .map(productSpecAttributeInput -> {
          PmsProductAttribute pmsProductSpecAttribute = this.assemblePmsProductAttribute(product, productSpecAttributeInput);
          List<PmsProductAttributeValue> pmsProductAttributeValues = this.assemblePmsProductSpecAttributeValue(product, pmsProductSpecAttribute,
              productSpecAttributeInput.getProductAttributeValues());
          return PmsProductAttributeAndValueBo.builder()
              .productAttribute(pmsProductSpecAttribute)
              .productAttributeValues(pmsProductAttributeValues)
              .build();
        })
        .collect(Collectors.toList());

    return PmsProductAttributeBo.builder()
        .attributeAndValues(pmsProductSpecAttributeBos)
        .build();
  }

  private List<PmsProductAttributeValue> assemblePmsProductSpecAttributeValue(PmsProduct product, PmsProductAttribute pmsProductAttribute,
      List<PmsProductAttributeValueSaveInput> pmsProductSpecAttributeValues) {
    return pmsProductSpecAttributeValues.stream()
        .map(pmsProductAttributeValueSaveInput -> this.convertToPmsProductSpecAttributeValue(product, pmsProductAttribute, pmsProductAttributeValueSaveInput))
        .collect(Collectors.toList());
  }

  private PmsProductAttributeValue convertToPmsProductSpecAttributeValue(PmsProduct product, PmsProductAttribute pmsProductAttribute,
      PmsProductAttributeValueSaveInput pmsProductAttributeValueSaveInput) {
    PmsProductAttributeValue pmsProductAttributeValue = new PmsProductAttributeValue();
    BeanUtils.copyProperties(pmsProductAttributeValueSaveInput, pmsProductAttributeValue);
    pmsProductAttributeValue.setPmsAppId(product.getPmsAppId());
    pmsProductAttributeValue.setProductId(product.getId());
    pmsProductAttributeValue.setProductAttributeId(pmsProductAttribute.getId());
    return pmsProductAttributeValue;
  }

  private PmsProductAttribute assemblePmsProductAttribute(PmsProduct product, PmsProductAttributeSaveInput pmsProductAttributeSaveInput) {
    PmsProductAttribute pmsProductSpecAttribute = new PmsProductAttribute();
    BeanUtils.copyProperties(pmsProductAttributeSaveInput, pmsProductSpecAttribute);
    pmsProductSpecAttribute.setProductId(product.getId());
    pmsProductSpecAttribute.setPmsAppId(product.getPmsAppId());
    return pmsProductSpecAttribute;
  }

  @Override
  public SaveContext<PmsProductAttribute> assemblePmsProductAttributeSaveContext(SaveContext<PmsProduct> pmsProductSaveContext, PmsProductAttributeSaveInput pmsProductAttributeSaveInput) {

    Optional<PmsSpecAttribute> pmsSpecAttributeOptional = this.getAndCheckPmsSpecAttribute(pmsProductAttributeSaveInput.getSpecAttributeId());
    PmsProduct pmsProduct = pmsProductSaveContext.getData();
    boolean isAdd = AceNumberUtils.isNullOrNegativeOrZero(pmsProductAttributeSaveInput.getId());
    PmsProductAttribute pmsProductAttribute = null;
    if (isAdd) {
      pmsProductAttribute = PmsProductAttribute.builder()
          .id(this.getNewId())
          .pmsAppId(pmsProduct.getPmsAppId())
          .productId(pmsProduct.getId())

          .build();
    } else {
      pmsProductAttribute = this.pmsProductAttributeRepository.findByIdAndPmsAppIdAndProductIdAndDeleteFlag(
          pmsProductAttributeSaveInput.getId(),
          pmsProduct.getPmsAppId(),
          pmsProduct.getId(),
          CoreConstant.DELETE_FLAG_NOT
      );
      AceAssertUtils.isNull(pmsProductAttribute, "无法修改商品属性,[%s]商品属性不存在", pmsProductAttributeSaveInput.getId());
    }
    String name = pmsSpecAttributeOptional
        .map(PmsSpecAttribute::getName)
        .orElse(pmsProductAttributeSaveInput.getName());
    Long specAttributeId = pmsSpecAttributeOptional
        .map(PmsSpecAttribute::getId)
        .orElse(CoreConstant.ZERO_LONG);
    BeanUtils.copyProperties(pmsProductAttributeSaveInput, pmsProductAttribute);
    pmsProductAttribute.setName(name);
    pmsProductAttribute.setSpecAttributeId(specAttributeId);
    return SaveContextUtils.of(pmsProductAttribute, isAdd);
  }

  private Optional<PmsSpecAttribute> getAndCheckPmsSpecAttribute(Long specAttributeId) {
    if (AceNumberUtils.isNullOrNegativeOrZero(specAttributeId)) {
      return Optional.empty();
    }
    PmsSpecAttribute pmsSpecAttribute = pmsSpecAttributeRepository.getById(specAttributeId);
    AceAssertUtils.isNull(pmsSpecAttribute, "[%s]规格属性不存在", specAttributeId);
    return Optional.of(pmsSpecAttribute);
  }
}
